import json
import time

from django.views import View
from django_redis import get_redis_connection
from django.http import JsonResponse
from apps.goods.models import SKU
from apps.users.models import Address
from utils.views import LoginRequiredJSONMixin
from apps.orders.models import OrderInfo, OrderGoods
from django.db import transaction


class OrderSettlementView(View):
    def get(self, request):
        # 获取用户信息
        user = request.user
        # 地址信息
        addresses = Address.objects.filter(is_deleted=False)

        # 将对象数据转换为字典数据
        address_list = []

        for address in addresses:
            address_list.append(
                {
                    'id': address.id,
                    'province': address.province.name,
                    'city': address.city.name,
                    'district': address.district.name,
                    'place': address.place,
                    'receiver': address.receiver,
                    'mobile': address.mobile,
                }
            )
        redis_cli = get_redis_connection('carts')
        pipeline = redis_cli.pipeline()
        pipeline.hgetall('carts_%s' % user.id)
        pipeline.smembers('selected_%s' % user.id)
        result = pipeline.execute()
        # 购物车选中信息
        selected_carts = {}
        # 我们接受管道统一执行后的结果 [hash结果， set结果]
        sku_id_counts = result[0]  # {sku_id: count}
        select_ids = result[1]  # {sku_id.....}
        for sku_id in select_ids:
            selected_carts[int(sku_id)] = int(sku_id_counts[sku_id])

        sku_list = []
        # 根据商品id查询商品具体信息 []
        for sku_id, count in selected_carts.items():
            sku = SKU.objects.get(pk=sku_id)
            sku_list.append(
                {
                    'id': sku.id,
                    'name': sku.name,
                    'count': count,
                    'default_image_url': sku.default_image.url,
                    'price': sku.price,
                }
            )
        from decimal import Decimal
        context = {
            'skus': sku_list,
            'addresses': address_list,
            'freight': Decimal('10')
        }
        return JsonResponse({'code': 0, 'errmsg': 'ok', 'context': context})


"""
生成订单：
    1. 接受数据、验证数据
    2. 数据入库
    3. 返回响应
前端:
    1.  携带数据 地址id, 支付方式 携带用户的session信息(cookies)
后端：
    先生成主表 商品基本信息，再生成从表
    
    金额需要后端自己算
    order_id 主键(自己生成）
    状态支付由支付方式决定
    3.1 保存订单基本信息
    3.2 再保存订单商品信息 --商品必须先选中才能给发送请求，选中后redis中的数据会变化
        链接redis
        获取hash
        获取set
        最好重新组织一个数据，这个数据是选中商品信息 {sku_id: count}
        判断库存是否充足
        如果充足，则库存减少，销量增加
        不充足， 下单失败
        累加总金额和总数量
        保存订单商品信息
     更新订单商品信息 -> 数量
     redis中将该商品给去除
"""


class OrderCommitView(LoginRequiredJSONMixin, View):
    def post(self, request):
        # 取用户
        user = request.user
        # 取数据
        data = json.loads(request.body.decode())
        # 验证数据
        address_id = data.get('address_id')
        pay_method = data.get('pay_method')
        if not all([address_id is not None, pay_method is not None]):
            return JsonResponse({'code': 400, 'errmsg': '参数不全'})
        try:
            address = Address.objects.get(id=address_id)
        except Address.DoesNotExist:
            return JsonResponse({'code': 400, 'errmsg': '参数不全'})
        if int(pay_method) not in [OrderInfo.PAY_METHODS_ENUM['CASH'], OrderInfo.PAY_METHODS_ENUM['ALIPAY']]:
            return JsonResponse({'code': 400, 'errmsg': '参数不全'})
        from django.utils import timezone
        # order_id逐渐自己生成
        order_id = timezone.localtime().strftime('%Y%m%d%H%M%S') + '%09d' % user.id

        # 支付状态 如果是货到付款
        if pay_method == OrderInfo.PAY_METHODS_ENUM['CASH']:
            status = OrderInfo.ORDER_STATUS_ENUM['UNSEND']
        else:
            status = OrderInfo.ORDER_STATUS_ENUM['UNPAID']

        # 总金额 * 总数量 计算金额 金额必须为 Decimal
        total_count = 0
        from decimal import Decimal
        total_amount = Decimal('0')  # 总金额
        freight = Decimal('10.00')
        # 数据入库 先入订单基本信息
        orderinfo = OrderInfo.objects.create(
            order_id=order_id,
            user=user,
            address=address,
            total_amount=total_amount,
            total_count=total_count,
            freight=freight,
            pay_method=pay_method,
            status=status,
        )

        # 链接数据库
        redis_cli = get_redis_connection('carts')
        pipeline = redis_cli.pipeline()
        pipeline.hgetall('carts_%s' % user.id)
        pipeline.smembers('selected_%s' % user.id)
        result = pipeline.execute()
        # 组织sku
        sku_list = {}
        for sku_id in result[1]:
            sku_list[int(sku_id)] = int(result[0][sku_id])

        # 验证订单数量
        for sku_id, count in sku_list.items():
            sku = SKU.objects.get(id=sku_id)
            if sku.stock < count:
                return JsonResponse({'code': 400, 'errmsg': '库存不足'})
            with transaction.atomic():
                point = transaction.savepoint()
                # 起始点
                while True:
                    # 2.8 如果库存充足， 则库存减少，销量增加
                    old_stock = sku.stock
                    # 更新的时候比对这个数据对不对
                    new_stock, new_sales = sku.stock - count, sku.sales + count
                    # 只有库存等于旧的库存的时候才能更新
                    result = SKU.objects.filter(id=sku_id, stock=old_stock).update(stock=new_stock, sales=new_sales)
                    if result == 0:
                        time.sleep(0.05)
                        continue
                    transaction.savepoint_rollback(point)
                    break

                orderinfo.total_count += count
                orderinfo.total_amount += (sku.price * count)
                orderinfo.save()
                # 保存订单信息
                OrderGoods.objects.create(
                    order=orderinfo,
                    sku=sku,
                    count=count,
                    price=sku.price,
                )
                orderinfo.total_amount += freight
                transaction.savepoint_commit(point)

        # 删除redis中的数据
        pl = redis_cli.pipeline()
        pl.hdel('carts_%s' % user.id, *result[1])
        pl.srem('selected_%s' % user.id, *result[1])
        pl.execute()

        return JsonResponse({'code': 0, 'errmsg': 'ok', 'order_id': order_id})


"""

订单的记录 使用乐观锁

"""
